package com.apkcore.camera2

import android.annotation.SuppressLint
import android.graphics.Bitmap
import android.graphics.Matrix
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.Surface
import android.view.View
import android.view.ViewGroup
import androidx.camera.core.*
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import com.apkcore.camera2.databinding.Camera2LayoutBinding
import com.apkcore.camera2.databinding.FragmentMainBinding
import com.apkcore.camera2.utils.YuvToRgbConverter
import com.google.common.util.concurrent.ListenableFuture
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min

/**
 * @author chanehao
 * @date 2023/03/22
 * @apiNote
 */
class MyFragment : Fragment() {
    private lateinit var fragmentMainBinding: FragmentMainBinding
    private var cameraUiContainerBinding: Camera2LayoutBinding? = null
    private val cameraExecutor: ExecutorService = Executors.newSingleThreadExecutor()
    private lateinit var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>
    private lateinit var camerax: Camera
    private val converter by lazy { YuvToRgbConverter(requireContext()) }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        fragmentMainBinding.pv.post {
            updateCameraUi()
            bindCameraUseCases(view)
        }
    }

    @SuppressLint("UnsafeOptInUsageError")
    private fun bindCameraUseCases(view: View) {
        cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
        val cameraSelector = CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()
        val rotation = fragmentMainBinding.pv.display.rotation

        val screenAspectRatio = aspectRatio(view.measuredWidth, view.measuredHeight)

        val preview = Preview.Builder()
            .setTargetAspectRatio(screenAspectRatio)
            .setTargetRotation(rotation)
            .build().also {
                it.setSurfaceProvider(fragmentMainBinding.pv.surfaceProvider)
            }
        cameraProviderFuture.addListener({
            val cameraProvider = cameraProviderFuture.get()
            cameraProvider.unbindAll()

            val imageAnalyzer = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                ImageAnalysis.Builder()
                    .setTargetAspectRatio(screenAspectRatio)
                    .setTargetRotation(rotation)
//                    .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
                    .setOutputImageRotationEnabled(true) // 是否旋转分析器中得到的图片
                    .setTargetRotation(Surface.ROTATION_0) // 允许旋转后 得到图片的旋转设置
                    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                    .build()
                    .also {
                        it.setAnalyzer(cameraExecutor) { imageProxy ->
                            val image = imageProxy.image
                            image?.let {

                                //RGBA时
//                                val buffer = image.planes[0].buffer
//                                val pixelStride = image.planes[0].pixelStride
//                                val rowStride = image.planes[0].rowStride
//                                val rowPadding = rowStride - pixelStride * image.width
//                                val bitmapBuffer = Bitmap.createBitmap(
//                                    image.width + rowPadding / pixelStride,
//                                    image.height,
//                                    Bitmap.Config.ARGB_8888
//                                )
//                                bitmapBuffer.copyPixelsFromBuffer(buffer)
//
                                val bitmapBuffer = Bitmap.createBitmap(image!!.width, image.height, Bitmap.Config.ARGB_8888)
                                converter.yuvToRgb(image, bitmapBuffer)
                                val rotationDegrees = imageProxy.imageInfo.rotationDegrees.toFloat()
                                val rotatedBitmap: Bitmap
                                if (rotationDegrees != 0f) {
                                    val matrix = Matrix().apply { postRotate(rotationDegrees) }
                                    rotatedBitmap = Bitmap.createBitmap(
                                        bitmapBuffer, 0, 0, image.width, image.height, matrix, true
                                    )
                                    // 如果需要，可以释放Image对象和Bitmap对象
                                    bitmapBuffer.recycle()
                                } else {
                                    rotatedBitmap = bitmapBuffer
                                }
                                imageProxy.close()
                                view.post {
                                    cameraUiContainerBinding?.img?.setImageBitmap(rotatedBitmap)
                                }
                            }

                        }
                    }
            } else {
                TODO("VERSION.SDK_INT < M")
            }

            try {
                camerax = cameraProvider.bindToLifecycle(
                    this, cameraSelector, preview, imageAnalyzer
                )
            } catch (exc: Exception) {
                Log.e(TAG, "Use case binding failed", exc)
            }
        }, ContextCompat.getMainExecutor(requireContext()))
    }

    private fun aspectRatio(width: Int, height: Int): Int {
        val previewRatio = max(width, height).toDouble() / min(width, height)
        if (abs(previewRatio - RATIO_4_3_VALUE) <= abs(previewRatio - RATIO_16_9_VALUE)) {
            return AspectRatio.RATIO_4_3
        }
        return AspectRatio.RATIO_16_9
    }

    private fun updateCameraUi() {
        cameraUiContainerBinding?.root?.let {
            fragmentMainBinding.root.removeView(it)
        }

        cameraUiContainerBinding = Camera2LayoutBinding.inflate(
            LayoutInflater.from(requireContext()),
            fragmentMainBinding.root,
            true
        )
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        fragmentMainBinding = FragmentMainBinding.inflate(inflater, container, false)
        return fragmentMainBinding.root
    }

    override fun onDestroy() {
        super.onDestroy()
        cameraExecutor.shutdown()
    }

    companion object {
        private const val TAG = "MyFragment"
        private const val RATIO_4_3_VALUE = 4.0 / 3.0
        private const val RATIO_16_9_VALUE = 16.0 / 9.0
    }
}